package si.unimb.src.wifisms.control;

import java.util.ArrayList;

import si.unimb.src.wifisms.entity.*;
import si.unimb.src.wifisms.util.Utility;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;

/**
 * 
 * @author Ales
 * 
 * Razred za asinhrono posiljanje SMS sporocil.
 * Med posiljanjem je prikazan ProgressDialog, ki se po zakljucku skrije.
 *
 */
public class AsyncDialogSender extends AsyncTask<SMSMessage, Void, Void> implements BatchSenderListener {

	protected ProgressDialog dialog;
	protected BatchSender batchSender;
	
	protected Context context;
	
	// dialog message
	protected String dialogTitle = "Pošiljam";
	protected String dialogMessage = "Pošiljanje je v teku";
	protected boolean isActive = false;
	protected boolean isCancelable = false;
	protected boolean canceled = false;
	
	// lock object (za sinhronizacijo)
	final protected Object lockObject = new Object();
	
	// Poslusalci, ki so se prijavili na dogodke
	protected ArrayList<TaskFinishListener> listeners = new ArrayList<TaskFinishListener>();
	
	/**
	 * 
	 * Privzeti konstruktor
	 * 
	 * @param parent Context Activityja, ki je poklical konstruktorja
	 */
	public AsyncDialogSender(Context parent) {
		
		// Ustvarimo dialog
		this.context = parent;
		dialog = new ProgressDialog(parent);
		dialog.setCancelable(true);
		dialog.setOnCancelListener(new SenderCancelListener(this));
		dialog.setTitle("Čakanje na internetno povezavo...");
		dialog.setMessage("Proces pošiljanja lahko trenutno še prekinete.");
		
		// Ustvarimo BatchSenderja in se prijavimo na njegove dogodke
		batchSender = new BatchSender(parent);
		batchSender.addListener(this);
		
		// lahko preklicemo
		isCancelable = true;
		
	}
	
	@Override
	protected Void doInBackground(SMSMessage... messages) {
		
		// Nimamo nic za poslati
		if(messages.length == 0) return null;
		
		// Drugace gremo posiljati sporocila
		for(SMSMessage message : messages) {
		
			batchSender.addMessage(message);
		
		}
		
		// Cakamo, dokler ne dobimo povezave
		while(!Utility.isConnected(context) && !canceled) {
			
			// Pocakamo na spremembo v povezavi
			ConnectivityReceiver.waitForConnectivityAction();
			
		}
		
		// Ce smo med cakanjem prekinili
		if(canceled) {

			return null;
			
		}
		
		publishProgress();
		
		try {
			
			// od tu naprej vec zadeve ne gre prekiniti
			isCancelable = false;
			batchSender.sendAll();
			isActive = true;
			waitForIt();
			
		} catch (InvalidTokenException e) {
			
			e.printStackTrace();
			
		}
		
		return null;
		
	}
	
	public void cancelSending() {
	
		// Ce je prekinljivo
		if(isCancelable) {
		
			canceled = true;
			ConnectivityReceiver.generateConnectivityAction();
		
		}
		
	}
	
	/**
	 * 
	 * Ali je task se aktiven ali ne.
	 * 
	 * @return True, ce je se aktiven. Drugace vrne false.
	 */
	public boolean isActive() {
		
		return isActive;
		
	}
	
	/**
	 * 
	 * Ali task se lahko prekinemo
	 * 
	 * @return True, ce lahko. Drugace vrne false.
	 */
	public boolean isCancelable() {
		
		return isCancelable;
		
	}

	/**
	 * 
	 * Metoda, ki caka tako dolgo, da se posiljanje zakljuci.
	 * Uporabno za sinhronizacijo in cakanje.
	 * 
	 */
	private void waitForIt() {

		synchronized(lockObject) {
		
			while(isActive) {
		
				try {
					
					lockObject.wait();
					
				} catch (InterruptedException e) {}
				
			}
		
		}
		
	}
	
	@Override
	protected void onProgressUpdate(Void... progress) {

		super.onProgressUpdate(progress);
		
		
		dialog.setTitle(dialogTitle);
		dialog.setMessage(dialogMessage);
		
		// dodamo eno piko (za naslednjic)
		dialogMessage += ".";
		
    }
	
	@Override
	protected void onPreExecute() {
		
		dialog.show();
		
	}
	
	@Override
	protected void onPostExecute(Void result) {

		super.onPostExecute(result);
		
		// Pobrisemo sporocila, ki so se uspesno poslala
		Database.removeSentMessages(context);
		
		// Shranimo stanje baze
		Database.persist(context);
		
		// Obvestimo vse poslusalce
		for(TaskFinishListener listener : listeners) {
			
			listener.onTaskFinish();
			
		}
		
		// Komaj na koncu odstranimo dialog (ker lahko shranjevanje traja nekaj casa)
		dialog.dismiss();
		
    }
	
	/*
	 * 
	 * Implementacija vmesnika BatchSenderListener
	 * 
	 */

	@Override
	public void onFinish() {

		// Sprostimo lock objekt
		synchronized(lockObject) {
			
			isActive = false;
			lockObject.notifyAll();
		
		}
		
		
	}

	@Override
	public void onStart() {}


	@Override
	public void onUpdate() {

		publishProgress();
		
	}
	
	/**
	 * 
	 * Prijava na dogodke
	 * 
	 * @param listener
	 */
	public void addListener(TaskFinishListener listener) {
		
		listeners.add(listener);
		
	}
	
	/**
	 * 
	 * Odjava iz dogodkov
	 * 
	 * @param listener
	 */
	public void removeListener(TaskFinishListener listener) {
		
		listeners.remove(listener);
		
	}

}

class SenderCancelListener implements OnCancelListener {

	private AsyncDialogSender parent;
	
	public SenderCancelListener(AsyncDialogSender parent) {
	
		this.parent = parent;
		
	}
	
	@Override
	public void onCancel(DialogInterface dialog) {

		parent.cancelSending();
		
	}
	
}
